// 版权归 瞄你个汪 所有。使用本代码应遵守相关法律法规和Apache 2.0开源许可要求。
package top.geeke.toolkit;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.GifCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.StrUtil;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.geeke.config.AppConfiguration;
import top.geeke.config.cache.RedisCache;
import top.geeke.constants.AppCachePool;
import top.geeke.controller.dto.CaptchaOutput;

import java.util.Arrays;
import java.util.Random;

/**
 * <p>
 * 验证码管理器
 * </p>
 * @author 瞄你个汪
 * @since 2024/6/5 22:13
 */
@Component
public class CaptchaManager {
    @Autowired
    private AppConfiguration appConfiguration;
    @Autowired
    private RedisCache redisCache;
    /**
     * 生成验证码
     */
    public CaptchaOutput generator(String id) {
        // 生成验证码
        AppConfiguration.Captcha config = appConfiguration.getCaptcha();
        GifCaptcha captcha = CaptchaUtil.createGifCaptcha(160, 50, codeGenerator(id), config.getThickness());
        return new CaptchaOutput(id, captcha.getImageBase64());
    }

    /**
     * 校验验证码
     * @param id 验证码ID
     * @param inputCode 验证值
     */
    public boolean verify(String id, String inputCode) {
        String code = redisCache.get(String.format(AppCachePool.SYSTEM_CAPTCHA, id));
        return inputCode.equals(code);
    }

    /**
     * 验证码算法
     * @param id 验证码ID
     */
    private CodeGenerator codeGenerator(String id) {
        return new CodeGenerator() {
            @Override
            public String generate() {
                Random random = new Random();
                boolean isAddition = new Random().nextBoolean();
                int numLen = appConfiguration.getCaptcha().getNumLength();
                int num1 = (int) (Math.pow(10, numLen - 1) + random.nextInt((int)(Math.pow(10, numLen) - Math.pow(10, numLen - 1))));
                int num2 = (int) (Math.pow(10, numLen - 1) + random.nextInt((int)(Math.pow(10, numLen) - Math.pow(10, numLen - 1))));
                int code = isAddition ? (num1 + num2) : (num1 - num2);

                redisCache.set(String.format(AppCachePool.SYSTEM_CAPTCHA, id), code + "", 60);
                return num1 + (isAddition ? "+" : "-") + num2;
            }

            @Override
            public boolean verify(String code, String userInputCode) {
                try {
                    if (Strings.isEmpty(code) || Strings.isEmpty(userInputCode) || !StrUtil.isNumeric(userInputCode)) return false;
                    Integer[] nums = Arrays.stream(code.split("[+-]"))
                            .map(Integer::parseInt)
                            .toArray(Integer[]::new);
                    return (code.contains("+") ? (nums[0] + nums[1]) : (nums[0] - nums[1])) == Integer.parseInt(userInputCode);
                } catch (Exception i) {
                    return false;
                }
            }
        };
    }
}
